<template>
	<view class="uv-toast">
		<uv-overlay :show="isShow && tmpConfig.overlay" :custom-style="overlayStyle"></uv-overlay>
		<uv-transition :show="isShow" mode="fade" :custom-style="aniStyle">
			<view
				class="uv-toast__content"
				ref="uvToastContent"
				:style="[contentStyle]"
				:class="[
					'uv-type-' + tmpConfig.type,
					tmpConfig.type === 'loading' || tmpConfig.loading ? 'uv-toast__content--loading' : ''
				]"
			>
				<uv-loading-icon
					v-if="tmpConfig.type === 'loading'"
					mode="circle"
					color="rgb(255, 255, 255)"
					inactiveColor="rgb(120, 120, 120)"
					size="25"
				></uv-loading-icon>
				<uv-icon
					v-else-if="tmpConfig.type !== 'defalut' && iconName"
					:name="iconName"
					size="17"
					:color="tmpConfig.type"
					:customStyle="iconStyle"
				></uv-icon>
				<uv-gap
					v-if="tmpConfig.type === 'loading' || tmpConfig.loading"
					height="12"
					bgColor="transparent"
				></uv-gap>
				<text
					class="uv-toast__content__text"
					:class="['uv-toast__content__text--' + tmpConfig.type]"
					style="max-width: 400rpx"
				>
					{{ tmpConfig.message }}
				</text>
			</view>
		</uv-transition>
	</view>
</template>
<script>
import { hexToRgb } from '@/uni_modules/uv-ui-tools/libs/function/colorGradient.js';
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom');
// #endif
/**
 * toast 消息提示
 * @description 此组件表现形式类似uni的uni.showToastAPI，但也有不同的地方。
 * @tutorial https://www.uvui.cn/components/toast.html
 * @property {Boolean}	loading		是否加载中 （默认 false ）
 * @property {String | Number}	zIndex	toast展示时的zIndex值 (默认 10090 )
 * @property {String | Number}	message		显示的文字内容
 * @property {String} icon 图标，或者绝对路径的图片
 * @property {String} type 主题类型 （默认 default）
 * @property {Boolean} overlay 是否显示透明遮罩，防止点击穿透 （默认 false ）
 * @property {String} position 位置 （默认 'center' ）
 * @property {Object} params 跳转的参数
 * @property {String | Number}  duration	展示时间，单位ms （默认 2000 ）
 * @property {Function} complete 执行完后的回调函数
 *
 * @event {Function} show 显示toast，如需一进入页面就显示toast，请在onReady生命周期调用
 * @example <uv-toast ref="uvToastRef" />
 */
export default {
	name: 'uv-toast',
	mixins: [mpMixin, mixin],
	data() {
		return {
			isShow: false,
			timer: null, // 定时器
			config: {
				message: '', // 显示文本
				type: '', // 主题类型，primary，success，error，warning，black
				duration: 2000, // 显示的时间，毫秒
				icon: true, // 显示的图标
				position: 'center', // toast出现的位置
				complete: null, // 执行完后的回调函数
				overlay: true, // 是否防止触摸穿透
				loading: false, // 是否加载中状态
				zIndex: 10090 //弹出的层级
			},
			tmpConfig: {}, // 将用户配置和内置配置合并后的临时配置变量
			rect: {},
			opacity: 0
		};
	},
	computed: {
		iconName() {
			// 只有不为none，并且type为error|warning|succes|info时候，才显示图标
			if (!this.tmpConfig.icon || this.tmpConfig.icon == 'none') {
				return '';
			}
			if (['error', 'warning', 'success', 'primary'].includes(this.tmpConfig.type)) {
				return this.$uv.type2icon(this.tmpConfig.type);
			} else {
				return '';
			}
		},
		overlayStyle() {
			const style = {
				justifyContent: 'center',
				alignItems: 'center',
				display: 'flex',
				zIndex: this.tmpConfig.zIndex
			};
			// 将遮罩设置为100%透明度，避免出现灰色背景
			style.backgroundColor = 'rgba(0, 0, 0, 0)';
			return style;
		},
		iconStyle() {
			const style = {};
			// 图标需要一个右边距，以跟右边的文字有隔开的距离
			style.marginRight = '4px';
			// #ifdef APP-NVUE
			// iOSAPP下，图标有1px的向下偏移，这里进行修正
			if (this.$uv.os() === 'ios') {
				style.marginTop = '-1px';
			}
			// #endif
			return style;
		},
		aniStyle() {
			const style = {
				position: 'fixed',
				zIndex: this.tmpConfig.zIndex
			};
			return style;
		},
		// 内容盒子的样式
		contentStyle() {
			const { windowWidth, windowHeight } = this.$uv.sys();
			const style = {
				position: 'fixed',
				top: '50%',
				left: '50%',
				// #ifdef APP-NVUE
				opacity: this.opacity
				// #endif
			};
			let value = 0;
			// #ifndef APP-NVUE
			// 根据top和bottom，对Y轴进行窗体高度的百分比偏移
			if (this.tmpConfig.position === 'top') {
				style.top = '25%';
			} else if (this.tmpConfig.position === 'bottom') {
				style.top = '75%';
			} else {
				value = '-50%';
			}
			style.transform = `translate(-50%,${value})`;
			// #endif
			// #ifdef APP-NVUE
			const { width = 0, height = 0 } = this.rect ? this.rect : {};
			if (width && height) {
				style.left = `${windowWidth * 0.5 - width / 2}px`;
				if (this.tmpConfig.position === 'top') {
					style.top = `${windowHeight * 0.5 - height / 2 - windowHeight * 0.25}px`;
				} else if (this.tmpConfig.position === 'bottom') {
					style.top = `${windowHeight * 0.5 - height / 2 + windowHeight * 0.25}px`;
				} else {
					style.top = `${windowHeight * 0.5 - height / 2}px`;
				}
			}
			// #endif
			return style;
		}
	},
	created() {
		// 通过主题的形式调用toast，批量生成方法函数
		['primary', 'success', 'error', 'warning', 'default', 'loading'].map((item) => {
			this[item] = (message) =>
				this.show({
					type: item,
					message
				});
		});
	},
	methods: {
		// 显示toast组件，由父组件通过this.$refs.xxx.show(options)形式调用
		show(options) {
			// 不将结果合并到this.config变量，避免多次调用uv-toast，前后的配置造成混乱
			this.tmpConfig = this.$uv.deepMerge(this.config, options);
			// 清除定时器
			this.clearTimer();
			this.isShow = true;
			//#ifdef APP-NVUE
			this.$nextTick(() => {
				this.$uv.sleep(100).then(async (res) => {
					this.rect = await this.queryRect();
					this.$nextTick(() => {
						this.opacity = 1;
					});
				});
			});
			// #endif
			this.timer = setTimeout(() => {
				// 倒计时结束，清除定时器，隐藏toast组件
				this.clearTimer();
				// 判断是否存在callback方法，如果存在就执行
				typeof this.tmpConfig.complete === 'function' && this.tmpConfig.complete();
			}, this.tmpConfig.duration);
		},
		// 查询内容高度
		queryRect() {
			return new Promise((resolve) => {
				const ref = this.$refs['uvToastContent'];
				dom.getComponentRect(ref, (res) => {
					resolve(res.size);
				});
			});
		},
		// 隐藏toast组件，由父组件通过this.$refs.xxx.hide()形式调用
		hide() {
			this.clearTimer();
		},
		clearTimer() {
			// #ifdef APP-NVUE
			this.opacity = 0;
			// #endif
			this.isShow = false;
			// 清除定时器
			clearTimeout(this.timer);
			this.timer = null;
		}
	},
	// #ifdef VUE2
	beforeDestroy() {
		this.clearTimer();
	},
	// #endif
	// #ifdef VUE3
	unmounted() {
		this.clearTimer();
	}
	// #endif
};
</script>
<style lang="scss" scoped>
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
$uv-toast-color: #fff !default;
$uv-toast-border-radius: 4px !default;
$uv-toast-border-background-color: #585858 !default;
$uv-toast-border-font-size: 14px !default;
$uv-toast-border-padding: 12px 20px !default;
$uv-toast-loading-border-padding: 20px 20px !default;
$uv-toast-content-text-color: #fff !default;
$uv-toast-content-text-font-size: 15px !default;
$uv-toast-uv-icon: 10rpx !default;
$uv-toast-uv-type-primary-color: $uv-primary !default;
$uv-toast-uv-type-primary-background-color: #ecf5ff !default;
$uv-toast-uv-type-primary-border-color: rgb(215, 234, 254) !default;
$uv-toast-uv-type-primary-border-width: 1px !default;
$uv-toast-uv-type-success-color: $uv-success !default;
$uv-toast-uv-type-success-background-color: #dbf1e1 !default;
$uv-toast-uv-type-success-border-color: #bef5c8 !default;
$uv-toast-uv-type-success-border-width: 1px !default;
$uv-toast-uv-type-error-color: $uv-error !default;
$uv-toast-uv-type-error-background-color: #fef0f0 !default;
$uv-toast-uv-type-error-border-color: #fde2e2 !default;
$uv-toast-uv-type-error-border-width: 1px !default;
$uv-toast-uv-type-warning-color: $uv-warning !default;
$uv-toast-uv-type-warning-background-color: #fdf6ec !default;
$uv-toast-uv-type-warning-border-color: #faecd8 !default;
$uv-toast-uv-type-warning-border-width: 1px !default;
$uv-toast-uv-type-default-color: #fff !default;
$uv-toast-uv-type-default-background-color: #585858 !default;
.uv-toast {
	&__content {
		@include flex;
		padding: $uv-toast-border-padding;
		border-radius: $uv-toast-border-radius;
		background-color: $uv-toast-border-background-color;
		color: $uv-toast-color;
		align-items: center;
		/* #ifndef APP-NVUE */
		max-width: 600rpx;
		/* #endif */
		position: relative;
		&--loading {
			flex-direction: column;
			padding: $uv-toast-loading-border-padding;
		}
		&__text {
			color: $uv-toast-content-text-color;
			font-size: $uv-toast-content-text-font-size;
			line-height: $uv-toast-content-text-font-size;
			&--default {
				color: $uv-toast-content-text-color;
			}
			&--error {
				color: $uv-error;
			}
			&--primary {
				color: $uv-primary;
			}
			&--success {
				color: $uv-success;
			}
			&--warning {
				color: $uv-warning;
			}
		}
	}
}
.uv-type-primary {
	color: $uv-toast-uv-type-primary-color;
	background-color: $uv-toast-uv-type-primary-background-color;
	border-color: $uv-toast-uv-type-primary-border-color;
	border-width: $uv-toast-uv-type-primary-border-width;
}
.uv-type-success {
	color: $uv-toast-uv-type-success-color;
	background-color: $uv-toast-uv-type-success-background-color;
	border-color: $uv-toast-uv-type-success-border-color;
	border-width: 1px;
}
.uv-type-error {
	color: $uv-toast-uv-type-error-color;
	background-color: $uv-toast-uv-type-error-background-color;
	border-color: $uv-toast-uv-type-error-border-color;
	border-width: $uv-toast-uv-type-error-border-width;
}
.uv-type-warning {
	color: $uv-toast-uv-type-warning-color;
	background-color: $uv-toast-uv-type-warning-background-color;
	border-color: $uv-toast-uv-type-warning-border-color;
	border-width: 1px;
}
.uv-type-default {
	color: $uv-toast-uv-type-default-color;
	background-color: $uv-toast-uv-type-default-background-color;
}
</style>
